// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __NC_GEN_EXPR_H__
#define __NC_GEN_EXPR_H__

#include <stdio.h>
#include "GenSymbol.hpp"

namespace ninf {
namespace gen {


class GenExprList;

class GenExpr
{
public:
  GenExprCode code;
  int      lineno; /* line number this node created */
  union { 
    GenExprList     *  lp;    /* code == LIST, XX_EXPR,  ...  */
    GenSymbol       *  sym;   /* code == NAME, TYPE, ...  */
    const char        *  str;	/* e_code == STRING */
    long                 ival;	/* e_code == INT_CONSTANT */
    double               fval;	/* e_code == FLOAT_CONSTANT */
  } v;

  GenExpr(GenExprCode code);
  GenExpr(GenExprCode code, GenExprList * lp);
  GenExpr(GenExprCode code, GenSymbol * sym);
  GenExpr(GenExprCode code, const char * str);
  GenExpr(GenExprCode code, long ival);
  GenExpr(GenExprCode code, double fval);

  void          print(FILE * fp);
  GenExprCode getCode()  {return code;}
  GenSymbol * getSymbol(){return v.sym;}
  const char *  getString(){return v.str;}
  int           getInt()   {return v.ival;}
  double        getFloat() {return v.fval;}
  
};

#include <Types.hpp>

	typedef ninf::lib::DataType DATA_TYPE;
	typedef ninf::lib::ModeType MODE_SPEC;

#define EXPR_CODE(x)    ((x)->code)
#define EXPR_SYM(x)     ((x)->v.sym)
#define EXPR_STR(x)     ((x)->v.str)
#define EXPR_FLOAT(x)   ((x)->v.fval)
#define EXPR_LIST(x)    ((x)->v.lp)
#define EXPR_INT(x)     ((x)->v.ival)
#define EXPR_TYPE(x)    ((DATA_TYPE)((x)->v.ival))
#define EXPR_MODE_SPEC(x)       ((MODE_SPEC)((x)->v.ival))
#define EXPR_LINENO(x)  ((x)->lineno)


class GenExprList{
public:
  GenExpr     * expr;
  GenExprList * next;

  
  GenExprList(GenExpr     * expr, GenExprList * next):
   expr(expr),  next(next){}
};

inline GenExpr * make_enode(GenExprCode code, int ival){
  return new GenExpr(code, (long) ival);
}

GenExpr * list0(GenExprCode code);
GenExpr * list1(GenExprCode code, GenExpr * x1);
GenExpr * list2(GenExprCode code, GenExpr * x1, GenExpr * x2);
GenExpr * list3(GenExprCode code, 
		   GenExpr * x1, GenExpr * x2,
		   GenExpr * x3);
GenExpr * list4(GenExprCode code, 
		  GenExpr * x1, GenExpr * x2,
		  GenExpr * x3, GenExpr * x4);

GenExpr * list_put_last(GenExpr * lx, GenExpr * lx2);

#define EXPR_ARG1(x)    (EXPR_LIST(x)->expr)
#define EXPR_ARG2(x)    (EXPR_LIST(x)->next->expr)
#define EXPR_ARG3(x)    (EXPR_LIST(x)->next->next->expr)
#define EXPR_ARG4(x)    (EXPR_LIST(x)->next->next->next->expr)

#define LIST_NEXT(lp)	((lp)->next)
#define LIST_ITEM(lp)	((lp)->expr)
#define FOR_ITEMS_IN_LIST(lp,x) \
  if(x != NULL) for(lp = EXPR_LIST(x); lp != NULL ; lp = LIST_NEXT(lp))

#ifndef FALSE 
#define FALSE (1 == 0)
#endif

#ifndef TRUE
#define TRUE (1 == 1)
#endif
}
}
#endif
